/*
 * =====================================================================================
 *
 *       Filename:  cl_assert.hxx
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  11/28/2011 02:23:17 PM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Ken Chen (Ken), chen_kenz@emc.com
 *        Company:  EMC
 *
 * =====================================================================================
 */

#ifndef _CL_ASSERT_HXX_
#define _CL_ASSERT_HXX_

#include <cstdlib>

// An implementaion from Andrei Alexandrescu
namespace neo
{

template<typename T> class CLAsserterEx;

class CLAsserter
{
public:
  CLAsserter(bool holds) 
    : m_holds(holds)
  {
  }
  
  virtual ~CLAsserter()
  {
  }

  bool Handle(const char* file, int line) const
  {
    return doHandle(file, line);
  }

  static CLAsserter create(bool holds)
  {
    return CLAsserter(holds);
  }

  template<class E>
  static CLAsserterEx<E> create(bool holds, const char* msg)
  {
    return CLAsserterEx<E>(holds, msg);
  }

protected:
  enum Action
  {
    GIVE_UP,
    THROW_UP,
    IGNORE,
  };

protected:
  virtual bool doHandle(const char* file, int line) const
  {
    if(m_holds)
    {
      return true;
    }

    switch(askUser(file, line))
    {
      case GIVE_UP:
        std::abort();
        break;

      case THROW_UP:
        break;

      case IGNORE:
        break;
    }
    return false;
  }

  Action askUser(const char* file, int line, const char* const msg = NULL) const
  {
    if(msg != NULL)
    {
      return THROW_UP;
    }
    return GIVE_UP; 
  }

protected:
  const bool m_holds;
};

template<typename E>
class CLAsserterEx: public CLAsserter
{
public:
  CLAsserterEx(bool holds, const char* msg)
    : CLAsserter(holds), m_msg(msg)
  {
  }

private:

  virtual bool doHandle(const char* file, int line) const
  {
    const CLAsserter::Action action = askUser(file, line, m_msg);
    if(action == CLAsserter::THROW_UP)
    {
      throw E(m_msg);
    }
    return CLAsserter::doHandle(file, line);
  }

private:
  const char* const m_msg;
};

#ifdef NDEBUG
#define ASSERT_IT true 
#else
#define ASSERT_IT false 
#endif

#define BREAK_INTO_DEBUGGER \
  do{ \
    __asm ("int $0x3"); \
  }while(0);

#define ASSERT \
  if(ASSERT_IT); else struct Local \
  { \
    Local(const CLAsserter& info) \
    { \
      if(!info.Handle(__FILE__, __LINE__)) \
      { \
        BREAK_INTO_DEBUGGER; \
      } \
    } \
  } localAsserter = CLAsserter::create

} // neo

#endif //_CL_ASSERT_HXX_

